/*
 * $Id: time.c 68 2009-02-25 03:15:52Z hyunghwan.chung $
 *
   Copyright 2005-2009 Chung, Hyung-Hwan.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an  BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
 */

#include <xp/bas/time.h>
#include <xp/bas/errno.h>

#ifdef _WIN32
#	define WIN_EPOCH_YEAR  ((xp_time_t)1601)
#	define WIN_EPOCH_MON   ((xp_time_t)1)
#	define WIN_EPOCH_DAY   ((xp_time_t)1)

#	define EPOCH_DIFF_YEARS (XP_EPOCH_YEAR - WIN_EPOCH_YEAR)
#	define EPOCH_DIFF_DAYS (EPOCH_DIFF_YEARS * 365 + EPOCH_DIFF_YEARS / 4 - 3)
#	define EPOCH_DIFF_SECS (EPOCH_DIFF_DAYS * 24 * 60 * 60)
#	define EPOCH_DIFF_MSECS (EPOCH_DIFF_SECS * XP_MSEC_IN_SEC)
#endif

#if defined(XP_USE_SYSCALL) && defined(XP_HAVE_SYS_SYSCALL_H)
#	include <sys/syscall.h>
#endif

#if defined(HAVE_UNISTD_H)
#	include <unistd.h>
#endif

int xp_gettime (xp_time_t* value)
{
#ifdef _WIN32
	SYSTEMTIME st;
	FILETIME ft;

	/* 
	 * MSDN: The FILETIME structure is a 64-bit value representing the 
	 *       number of 100-nanosecond intervals since January 1, 1601 (UTC).
	 */

	GetSystemTime (&st);
	if (SystemTimeToFileTime (&st, &ft) == FALSE) return -1;
	*value = ((xp_time_t)(*((xp_int64_t*)&ft)) / (10 * 1000));
	*value -= EPOCH_DIFF_MSECS;
	return 0;
#else
	xp_timeval_t tv;
	int n;

#ifdef SYS_gettimeofday 
	n = syscall (SYS_gettimeofday, &tv, XP_NULL);
#else
	n = gettimeofday (&tv, XP_NULL);
#endif

	if (n == -1) return -1;
	*value = XP_TIMEVAL_TO_TIME (tv);
	return 0;
#endif
}

int xp_settime (xp_time_t value)
{
#ifdef _WIN32
	FILETIME ft;
	SYSTEMTIME st;

	*((xp_int64_t*)&ft) = ((value + EPOCH_DIFF_MSECS) * (10 * 1000));
	if (FileTimeToSystemTime (&ft, &st) == FALSE) return -1;
	if (SetSystemTime(&st) == FALSE) return -1;
	return 0;
#else
	xp_timeval_t tv;
	int n;
	XP_TIME_TO_TIMEVAL (value, &tv);

#ifdef SYS_settimeofday
	n = syscall (SYS_settimeofday, &tv, XP_NULL);
#else
	n = settimeofday (&tv, XP_NULL);
#endif

	if (n == -1) return -1;
	return 0;
#endif
}

